home *** CD-ROM | disk | FTP | other *** search
- ;===================================================
- ; PROGRAM ENCRYPT Version 3.0 by Dave Whitman
- ;
- ; Filter to encrypt/decrypt files.
- ;
- ; Syntax: ENCRYPT [?] [/key] [<infile] [>outfile]
- ;
- ; Reads stdin, encrypts data and writes it to stdout.
- ; Already encrypted files will be decrypted.
- ;
- ; An optional "key" word can be specified.
- ; If a key is specified, it must also be used in
- ; decrypting the file.
- ;
- ; The ? option prints a help message.
- ;
- ; Requires DOS 2.0, will abort under earlier versions.
- ;====================================================
-
- ;===============================================================
- ; Discussion:
- ;
- ; ENCRYPT modifies each character by XORing it with a "mask", a
- ; pattern of bits. XOR has the following truth table:
- ;
- ; XOR | 0 1 data bit
- ; ----|--------
- ; mask 0 | 0 1 result
- ; bit 1 | 1 0 of XOR
- ;
- ; Anywhere the mask has a 0 bit, the data will be unmodified. A
- ; 1 bit in the mask will invert the state of a data bit. For
- ; example:
- ;
- ; data byte: 10000001 (character "A")
- ; mask byte: 11110000
- ; XOR -----------
- ; 01110001 (encrypted to character "G")
- ;
- ; Aside from encryption, use XOR any time you want to flip the state
- ; of one or more bits. Use a mask with 1's in the positions you
- ; want to flip, and 0's in positions you want left alone.
- ;
- ; XOR has the interesting property of being its own inverse. If
- ; you XOR data with a mask, then XOR again with the same mask,
- ; you recover the original data. Try this example, it works!
- ;
- ; data byte: 01110001 (encrypted character "G" from above)
- ; mask byte: 11110000
- ; XOR ----------
- ; 10000001 (decrypted character "A")
- ;
- ; To make the encryption a little tougher to crack, ENCRYPT
- ; modifies the mask after each use, by performing a 1 bit rotate
- ; (instruction ROL, rotate left). Since the mask is 8 bits wide,
- ; a total of 8 different masks are generated:
- ;
- ; 11110000 initial mask
- ; 11100001 rotate left one bit (note wrap-around)
- ; 11000011 "
- ; 10000111 "
- ; 00001111 "
- ; 00011110 "
- ; 00111100 "
- ; 01111000 "
- ; 11110000 back to initial mask
- ;================================================================
- ;============
- ; Equates
- ;============
- ;DOS call codes
- @read equ 3FH ;read file/device
- @write equ 40H ;write file/device
- @dosver equ 30H ;get dos version
- @prnstr equ 09H ;print string
-
- cr equ 0DH ;carriage return character
- lf equ 0AH ;line feed character
- scrambler equ 10101010B ;mask to scramble key
-
- stdin equ 0000H ;standard input handle
- stdout equ 0001H ;standard output handle
-
- buf_size equ 2000 ;size of input and output buffers
-
- ;fields in program segment prefix
- param_count equ [80H] ;number of command line characters
- param_area equ [81H] ;command line characters
- mem_avail equ [06H] ;memory available in segment
-
-
- main proc far
- call setup ;check dos, parse options
- call process ;encrypt data
- int 20H ;and return to dos
- endp
-
- ;======================================
- ; SUBROUTINE SETUP
- ; Checks for proper DOS, parses options
- ;======================================
- setup proc near
-
- mov ah, @dosver ;what dos are we under?
- int 21H
- cmp al, 2 ;2.0 or over?
- jae a_mem ;yes, skip
-
- mov ah, @prnstr ;no, bitch
- mov dx, offset(baddos)
- int 21H
- pop ax ;reset stack
- int 20H ;and exit
-
- a_mem mov ax, mem_avail ;do we have room for the buffers?
- cmp ax, buf_size*2 ;two buffers, each buf_size long
- jae a_help ;yes, skip
- mov ah, @prnstr ;no, bitch
- mov dx, offset(nomem)
- int 21H
- pop ax ;reset stack
- int 20H ;and exit
-
- a_help xor ch,ch ;cx <== param count (clear out ch)
- mov cl, param_count ; " (fill in cl)
- cmp cl, 00H ;any params?
- je a_exit ;return if none
-
- mov di, offset(param_area) ;scan for help request
- mov al, '?'
- cld ;scan up, not down
- repnz ;repeat until matched or end
- scasb ;scan for ?
- jnz a_key ;reached end, no match? skip
- mov ah, @prnstr ;found ?, so print help
- mov dx, offset(help)
- int 21H
- pop ax ;pop stack
- int 20H ;and exit
-
- a_key mov di, offset(param_area) ;scan for key
- xor ch, ch ;cx <== param count
- mov cl, param_count ; "
- mov al, '/' ;key marked with "/"
- cld ;scan up, not down
- repnz ;repeat until matched or end
- scasb ;scan for /
- jnz a_exit ;reached end, no match? exit
-
- ;=================================================================
- ; Here we copy the key from the command line into a buffer for use
- ; during encryption. During copying, we scramble it somewhat, to
- ; disguise it. During testing of earlier versions, it was noted that
- ; the key would be repeated many times in the encrypted text. The problem
- ; is that the space character (20H) encrypts to the key character used,
- ; but shifted in case. Since spaces often come in groups, the key word
- ; gets copied out into the output (poor security!). Scrambling the key
- ; at least ensures that the key doesn't stand out like a sore thumb.
- ;==================================================================
-
- mov si, di ;si points to 1st char of key
- mov di, offset(key+1) ;di points to key buffer
- ;cx has param chars left
- xor bx, bx ;bl counts key characters
- ;copy the mask:
- copy_key lodsb ;get key character
- cmp al, ' ' ;terminate with space (or end of chars)
- je ck_exit
- xor al, scrambler ;scramble key
- stosb ;add char to key buffer
- inc bl ;bump char count
- loop copy_key ;and loop
- ck_exit mov key, bl ;save count
-
- a_exit ret
-
- baddos db cr lf 'This program requires DOS 2.0!' cr, lf, '$'
-
- nomem db cr lf 'Insufficient memory, program aborted' cr lf '$'
-
- help db cr lf
- db 'ENCRYPT version 3.0 by D. Whitman' cr lf
- db cr lf
- db 'Syntax: ENCRYPT [?] [/key] [<infile] [>outfile]' cr lf
- db cr lf
- db 'Reads stdin, encrypts data, and writes it to stdout.' cr lf
- db 'If file is already encrypted, it will be decrypted.' cr lf
- db cr lf
- db 'An optional "key" word can be specified.' cr lf
- db 'If used, the key must also be specified when decrypting'
- db ' the file.' cr lf
- db cr lf
- db 'The ? option prints this help message.' cr lf
- db cr lf
- db 'Encrypted text is unintelligable, and cannot be'
- db ' decoded by simple' cr lf
- db 'substitution. However, the encryption algorithm is'
- db ' by no means unbreakable.' cr lf
- db 'Encryption should not be used as a replacement for'
- db ' proper security' cr lf
- db 'with extremely sensitive data.' cr lf
- db cr lf
- db 'Warning: editing of encrypted files can scramble them'
- db ' beyond recovery!' cr lf
- db cr lf
- db 'This program is in the public domain.' cr lf
- db '$'
- endp
-
- ;=========================================
- ; SUBROUTINE PROCESS
- ;
- ; 1. load input buffer
- ; 2. convert each char, pass to output buffer
- ; 3. dump output buffer
- ; 4. repeat until EOF
- ;==========================================
-
- process proc near
-
- mov di, offset(buf_out) ;point to output buffer
- movw outnum, 0 ;output buffer is empty
- mov bx, 0001H ;bx holds current offset in key buffer
- call fillbuf ;load input buffer
- cmp cx, 0000H ;any characters available?
- je p_exit ;nope, exit
-
- p1 call getchar ;get next char in al
- jc p_done ;carry flag set means none available
- call getkey ;get a key character in dl
- xor al, dl ;encrypt character
- call putchar ;output character
- jmps p1 ;and loop till done
-
- p_done cmpw outnum, 0 ;input done. any outstanding output?
- jle p_exit ;nope, exit
- call dumpbuf ;yes, empty buffer
-
- p_exit ret
- endp
-
- ;======================================================
- ; SUBROUTINE GETCHAR
- ;
- ; Trys to get a character from the input buffer.
- ; If sucessful, returns with character in AL, and carry
- ; flag clear. If unsucessful, sets zero flag.
- ;======================================================
- getchar proc near
- cmp cx, 0000 ;is the buffer empty?
- jne g1 ;nope, skip
- call fillbuf ;if so, try to refill it
- cmp cx, 0000 ;still empty?
- je g_abort ;then return failure
-
- g1 lodsb ;get character from [si]
- dec cx ;used up one char
- clc ;clear flag to indicate sucess
- ret ;and return
-
- g_abort stc ;set flag for failure
- ret
- endp
-
- ;======================================================
- ; SUBROUTINE FILLBUF
- ;
- ; Fills the input buffer from StdIn. The number of
- ; available characters is stored in CX, and SI is reset
- ; to the beginning of the buffer.
- ;======================================================
- fillbuf proc near
- push bx ;save position in key buffer
- mov ah, @read ;read
- mov bx, stdin ;from stdin
- mov cx, buf_size ;one buffer's worth
- mov dx, offset(buf_in) ;into the input buffer
- int 21H
- mov cx, ax ;save number of chars read
- mov si, offset(buf_in) ;reset buffer
- pop bx ;restore key buffer position
- ret
- endp
-
- ;==================================================
- ; SUBROUTINE GETKEY
- ;
- ; Gets a key byte from the key buffer. The byte
- ; is returned in DL.
- ;
- ; Each character from the key word is used sucessively.
- ; To maximize confusion, the byte is rotated before each use.
- ;====================================================
-
- getkey proc near
- mov dl, offset(key)[bx] ;get key byte
- rolb offset(key)[bx] ;rotate it for next use
- inc bl ;point to next character
- cmp bl, key ;have we run out of characters?
- jle gk_exit ;nope, exit
- mov bl, 01H ;yes, start back at beginning
- gk_exit ret
- endp
-
- ;===================================================
- ; SUBROUTINE PUTCHAR
- ;
- ; Moves the character in AL into the output buffer.
- ; If the buffer is now full, it is dumped to disk.
- ;===================================================
-
- putchar proc near
- stosb ;move character into buffer
- incw outnum ;bump count of chars in buffer
- cmpw outnum, buf_size ;is buffer full?
- jl pu_exit ;no, skip
- call dumpbuf ;yes, dump buffer to disk
- pu_exit ret
- endp
-
- ;==================================================
- ; SUBROUTINE DUMPBUF
- ;
- ; Dumps the output buffer to StdOut.
- ;==================================================
- dumpbuf proc near
- push ax ;save active registers
- push bx ; " " "
- push cx ; " " "
- push dx ; " " "
- mov ah, @write ;write
- mov bx, stdout ;to stdout
- mov cx, outnum ;number of chars for output
- mov dx, offset(buf_out) ;from output buffer
- int 21H
- movw outnum, 0 ;reset buffer
- mov di, offset(buf_out) ; " "
- pop dx ;restore active registers
- pop cx ; " " "
- pop bx ; " " "
- pop ax ; " " "
- ret
- endp
-
- ;=================
- ;GLOBAL VARIABLES
- ;=================
- outnum dw 0000H ;number of characters in output buffer
-
- ;=====================================================
- ;BUFFERS
- ;
- ; No space is actually allocated for the buffers.
- ; At run time, the program checks to ensure there
- ; is suffcient free memory, then uses the memory
- ; immediately after itself for buffers.
- ;
- ; This stratagy minimizes the size of the object file,
- ; and lets the program load quicker.
- ;======================================================
-
- key db 01H ;number of characters in key
- db 01H ;key text
- ds 128 ; " "
-
- buf_in
-
- org offset($+buf_size) ;this is a trick to set the address
- ;the output buffer.
- ;the address of buf_out is set to be
- ;the offset of the input buffer, plus
- ;the buffer length.
-
- buf_out ;output buffer